using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;
using JGSY.CMS.LowCode.Platform.Infrastructure.Services;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Middleware
{
    /// <summary>
    /// 租户解析中间件
    /// 负责从多种来源识别和验证租户身份
    /// </summary>
    public class TenantResolutionMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<TenantResolutionMiddleware> _logger;
        private readonly IMemoryCache _cache;

        // 租户解析策略优先级
        private readonly List<TenantResolutionStrategy> _strategies;

        public TenantResolutionMiddleware(
            RequestDelegate next,
            ILogger<TenantResolutionMiddleware> logger,
            IMemoryCache cache)
        {
            _next = next;
            _logger = logger;
            _cache = cache;

            // 按优先级排序的解析策略
            _strategies = new List<TenantResolutionStrategy>
            {
                TenantResolutionStrategy.Subdomain,    // 最高优先级
                TenantResolutionStrategy.Header,       // 高优先级
                TenantResolutionStrategy.JWT,          // 中优先级
                TenantResolutionStrategy.QueryString,  // 低优先级
                TenantResolutionStrategy.RoutePrefix   // 最低优先级
            };
        }

        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                // 从请求服务中获取所需的作用域服务
                var tenantService = context.RequestServices.GetRequiredService<ITenantService>();
                var tenantContext = context.RequestServices.GetRequiredService<ITenantContext>();

                // 跳过不需要租户解析的路径
                if (ShouldSkipTenantResolution(context.Request.Path))
                {
                    await _next(context);
                    return;
                }

                // 解析租户ID
                var tenantId = await ResolveTenantIdAsync(context, tenantService);

                if (!string.IsNullOrEmpty(tenantId))
                {
                    // 验证租户有效性
                    var isValidTenant = await ValidateTenantAsync(tenantId, tenantService);
                    
                    if (!isValidTenant)
                    {
                        _logger.LogWarning("无效的租户ID: {TenantId}, IP: {ClientIP}", 
                            tenantId, context.Connection.RemoteIpAddress);
                        
                        await HandleTenantNotFoundAsync(context);
                        return;
                    }

                    // 设置租户上下文
                    tenantContext.SetTenant(tenantId);
                    context.Items["TenantId"] = tenantId; // 保持向后兼容性
                    context.Items["TenantResolved"] = true;

                    // 更新租户最后活动时间（异步，不等待）
                    _ = Task.Run(() => UpdateTenantActivityAsync(tenantId, tenantService));

                    _logger.LogDebug("租户解析成功: {TenantId}, 策略: {Strategy}, Path: {Path}", 
                        tenantId, context.Items["TenantResolutionStrategy"], context.Request.Path);
                }
                else
                {
                    // 如果是需要租户的API路径但未能解析到租户，返回错误
                    if (RequiresTenant(context.Request.Path))
                    {
                        _logger.LogWarning("未能解析租户ID: Path: {Path}, IP: {ClientIP}", 
                            context.Request.Path, context.Connection.RemoteIpAddress);
                        
                        await HandleTenantNotFoundAsync(context);
                        return;
                    }
                }

                await _next(context);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "租户解析过程中发生错误: Path: {Path}", context.Request.Path);
                
                // 继续执行，避免因租户解析失败而中断整个请求
                await _next(context);
            }
        }

        /// <summary>
        /// 从多种来源解析租户ID
        /// </summary>
        private async Task<string?> ResolveTenantIdAsync(HttpContext context, ITenantService tenantService)
        {
            foreach (var strategy in _strategies)
            {
                string? tenantId = null;

                switch (strategy)
                {
                    case TenantResolutionStrategy.Subdomain:
                        tenantId = await ResolveFromSubdomainAsync(context, tenantService);
                        break;
                    case TenantResolutionStrategy.Header:
                        tenantId = ResolveFromHeader(context);
                        break;
                    case TenantResolutionStrategy.JWT:
                        tenantId = ResolveFromJWT(context);
                        break;
                    case TenantResolutionStrategy.QueryString:
                        tenantId = ResolveFromQueryString(context);
                        break;
                    case TenantResolutionStrategy.RoutePrefix:
                        tenantId = ResolveFromRoutePrefix(context);
                        break;
                }

                if (!string.IsNullOrEmpty(tenantId))
                {
                    context.Items["TenantResolutionStrategy"] = strategy.ToString();
                    return tenantId;
                }
            }

            return null;
        }

        /// <summary>
        /// 从子域名解析租户ID
        /// 格式: https://tenant-name.yourdomain.com
        /// </summary>
        private async Task<string?> ResolveFromSubdomainAsync(HttpContext context, ITenantService tenantService)
        {
            try
            {
                var host = context.Request.Host.Value;
                if (string.IsNullOrEmpty(host))
                {
                    return null;
                }

                var subdomain = ExtractSubdomain(host);
                if (string.IsNullOrEmpty(subdomain))
                {
                    return null;
                }

                // 从缓存或数据库查找租户
                var cacheKey = $"subdomain_tenant_{subdomain}";
                if (_cache.TryGetValue(cacheKey, out string? cachedTenantId))
                {
                    return cachedTenantId;
                }

                var tenant = await tenantService.GetTenantBySubdomainAsync(subdomain);
                if (tenant != null)
                {
                    _cache.Set(cacheKey, tenant.TenantId, TimeSpan.FromMinutes(30));
                    return tenant.TenantId;
                }

                return null;
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "从子域名解析租户ID失败: {Host}", context.Request.Host.Value);
                return null;
            }
        }

        /// <summary>
        /// 从HTTP Header解析租户ID
        /// Header: X-Tenant-ID: tenant-uuid
        /// </summary>
        private string? ResolveFromHeader(HttpContext context)
        {
            context.Request.Headers.TryGetValue("X-Tenant-ID", out var tenantHeader);
            var tenantId = tenantHeader.FirstOrDefault();
            
            return !string.IsNullOrEmpty(tenantId) ? tenantId : null;
        }

        /// <summary>
        /// 从JWT Token解析租户ID
        /// </summary>
        private string? ResolveFromJWT(HttpContext context)
        {
            try
            {
                var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
                if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer "))
                {
                    return null;
                }

                var token = authHeader.Substring("Bearer ".Length).Trim();
                if (string.IsNullOrEmpty(token))
                {
                    return null;
                }

                var handler = new JwtSecurityTokenHandler();
                if (!handler.CanReadToken(token))
                {
                    return null;
                }

                var jwtToken = handler.ReadJwtToken(token);
                var tenantClaim = jwtToken.Claims.FirstOrDefault(c => 
                    c.Type == "tenant_id" || c.Type == "tenantId" || c.Type == ClaimTypes.GroupSid);

                return tenantClaim?.Value;
            }
            catch (Exception ex)
            {
                _logger.LogDebug(ex, "从JWT Token解析租户ID失败");
                return null;
            }
        }

        /// <summary>
        /// 从查询字符串解析租户ID
        /// 格式: ?tenant=tenant-uuid
        /// </summary>
        private string? ResolveFromQueryString(HttpContext context)
        {
            context.Request.Query.TryGetValue("tenant", out var tenantQuery);
            var tenantId = tenantQuery.FirstOrDefault();
            
            return !string.IsNullOrEmpty(tenantId) ? tenantId : null;
        }

        /// <summary>
        /// 从路由前缀解析租户ID
        /// 格式: /tenant/tenant-uuid/api/...
        /// </summary>
        private string? ResolveFromRoutePrefix(HttpContext context)
        {
            var path = context.Request.Path.Value;
            if (string.IsNullOrEmpty(path))
            {
                return null;
            }

            var segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
            if (segments.Length >= 2 && segments[0].Equals("tenant", StringComparison.OrdinalIgnoreCase))
            {
                return segments[1];
            }

            return null;
        }

        /// <summary>
        /// 验证租户有效性（带缓存）
        /// </summary>
        private async Task<bool> ValidateTenantAsync(string tenantId, ITenantService tenantService)
        {
            var cacheKey = $"tenant_valid_{tenantId}";
            
            if (_cache.TryGetValue(cacheKey, out bool cachedResult))
            {
                return cachedResult;
            }

            var isValid = await tenantService.ValidateTenantAsync(tenantId);
            
            // 缓存验证结果（较短时间，确保及时更新状态）
            _cache.Set(cacheKey, isValid, TimeSpan.FromMinutes(5));
            
            return isValid;
        }

        /// <summary>
        /// 更新租户最后活动时间
        /// </summary>
        private async Task UpdateTenantActivityAsync(string tenantId, ITenantService tenantService)
        {
            try
            {
                                        await tenantService.RecordTenantActivityAsync(tenantId);
            }
            catch (Exception ex)
            {
                _logger.LogDebug(ex, "更新租户活动时间失败: {TenantId}", tenantId);
            }
        }

        /// <summary>
        /// 提取子域名
        /// </summary>
        private string? ExtractSubdomain(string host)
        {
            if (string.IsNullOrEmpty(host))
            {
                return null;
            }

            // 移除端口号
            var hostWithoutPort = host.Split(':')[0];
            var parts = hostWithoutPort.Split('.');
            
            // 需要至少3个部分才能有子域名 (subdomain.domain.com)
            if (parts.Length < 3)
            {
                return null;
            }

            var subdomain = parts[0];
            
            // 排除常见的非租户子域名
            var excludedSubdomains = new[] { "www", "api", "admin", "app", "mail", "ftp" };
            if (excludedSubdomains.Contains(subdomain.ToLowerInvariant()))
            {
                return null;
            }

            return subdomain;
        }

        /// <summary>
        /// 判断是否应该跳过租户解析
        /// </summary>
        private bool ShouldSkipTenantResolution(PathString path)
        {
            var pathValue = path.Value?.ToLowerInvariant() ?? "";
            
            // 系统级API和资源不需要租户解析
            var skipPaths = new[]
            {
                "/health",
                "/swagger",
                "/api/system",
                "/api/auth/login",
                "/api/auth/register",
                "/api/tenants", // 租户管理API可能不需要租户上下文
                "/.well-known",
                "/favicon.ico",
                "/robots.txt"
            };

            return skipPaths.Any(skip => pathValue.StartsWith(skip));
        }

        /// <summary>
        /// 判断路径是否需要租户
        /// </summary>
        private bool RequiresTenant(PathString path)
        {
            var pathValue = path.Value?.ToLowerInvariant() ?? "";
            
            // 大部分API都需要租户上下文
            return pathValue.StartsWith("/api/") && 
                   !pathValue.StartsWith("/api/system/") &&
                   !pathValue.StartsWith("/api/auth/") &&
                   !pathValue.StartsWith("/api/tenants/");
        }

        /// <summary>
        /// 处理租户未找到的情况
        /// </summary>
        private async Task HandleTenantNotFoundAsync(HttpContext context)
        {
            context.Response.StatusCode = 404;
            context.Response.ContentType = "application/json";
            
            var response = new
            {
                error = "Tenant not found",
                message = "请检查租户配置或联系管理员",
                timestamp = DateTime.UtcNow
            };

            await context.Response.WriteAsync(System.Text.Json.JsonSerializer.Serialize(response));
        }
    }

    /// <summary>
    /// 租户解析策略枚举
    /// </summary>
    public enum TenantResolutionStrategy
    {
        /// <summary>
        /// 子域名策略 (最高优先级)
        /// </summary>
        Subdomain,
        
        /// <summary>
        /// HTTP Header策略
        /// </summary>
        Header,
        
        /// <summary>
        /// JWT Token策略
        /// </summary>
        JWT,
        
        /// <summary>
        /// 查询字符串策略
        /// </summary>
        QueryString,
        
        /// <summary>
        /// 路由前缀策略 (最低优先级)
        /// </summary>
        RoutePrefix
    }

    /// <summary>
    /// 租户解析中间件扩展
    /// </summary>
    public static class TenantResolutionMiddlewareExtensions
    {
        /// <summary>
        /// 添加租户解析中间件
        /// </summary>
        public static IApplicationBuilder UseTenantResolution(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<TenantResolutionMiddleware>();
        }
    }
}
